package com.globefrog.framework.juc.executor.health;

import com.globefrog.framework.juc.executor.CustomExecutor;
import com.google.common.collect.Maps;
import java.beans.ConstructorProperties;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;

/**
 * 自定义线程池健康指标.
 *
 * @author : caijinbang
 * @date : Create in 2021-01-30
 */
public class CustomExecutorHealthIndicator implements HealthIndicator {

  private CustomExecutor customExecutor;

  @ConstructorProperties({"customExecutor"})
  public CustomExecutorHealthIndicator(CustomExecutor customExecutor) {
    this.customExecutor = customExecutor;
  }


  @Override
  public Health health() {
    Map<String, Object> executorMap = Maps.newLinkedHashMap();
    // 核心线程数
    int corePoolSize = customExecutor.getCorePoolSize();
    executorMap.put("核心线程数", corePoolSize);

    // 活跃线程数
    int activeCount = customExecutor.getActiveCount();
    executorMap.put("当前活跃线程数", activeCount);

    // 完成的任务数
    long completedTaskCount = customExecutor.getCompletedTaskCount();
    executorMap.put("完成的任务数", completedTaskCount);

    // 线程数历史高峰线
    int largestPoolSize = customExecutor.getLargestPoolSize();
    executorMap.put("线程峰值", largestPoolSize);

    // 当前池中线程数
    int poolSize = customExecutor.getPoolSize();
    executorMap.put("当前池中线程数", poolSize);

    BlockingQueue<Runnable> queue = customExecutor.getQueue();
    // 队列剩余空间数
    int remainingCapacity = queue.remainingCapacity();
    executorMap.put("队列剩余大小", remainingCapacity);

    // 队列中的任务
    long queueSize = customExecutor.getQueueSize();
    executorMap.put("当前队列中的任务数", queueSize);

    // 最大线程数
    int maximumPoolSize = customExecutor.getMaximumPoolSize();
    executorMap.put("设置最大线程数", maximumPoolSize);

    // 计划执行的近似任务总数
    long taskCount = customExecutor.getTaskCount();
    executorMap.put("计划执行的任务总数", taskCount);

    //如果当前活跃线程数 大于  80%的最大线程数，就认证是down
    double rate = BigDecimal.valueOf(activeCount)
        .divide(BigDecimal.valueOf(maximumPoolSize), 2, BigDecimal.ROUND_HALF_UP)
        .doubleValue();
    if (rate > 0.8) {
      return Health.down().withDetails(executorMap).build();
    } else {
      return Health.up().withDetails(executorMap).build();
    }
  }
}
